package gofish.dao;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.servlet.ServletContext;

import com.amazonaws.auth.PropertiesCredentials;
import com.amazonaws.services.simpledb.AmazonSimpleDB;
import com.amazonaws.services.simpledb.AmazonSimpleDBClient;
import com.amazonaws.services.simpledb.model.Attribute;
import com.amazonaws.services.simpledb.model.BatchDeleteAttributesRequest;
import com.amazonaws.services.simpledb.model.BatchPutAttributesRequest;
import com.amazonaws.services.simpledb.model.DeletableItem;
import com.amazonaws.services.simpledb.model.DeleteAttributesRequest;
import com.amazonaws.services.simpledb.model.Item;
import com.amazonaws.services.simpledb.model.PutAttributesRequest;
import com.amazonaws.services.simpledb.model.ReplaceableAttribute;
import com.amazonaws.services.simpledb.model.ReplaceableItem;
import com.amazonaws.services.simpledb.model.SelectRequest;

/**
 * 
 * @author kylyn
 *
 */

public class GoFishDAO {
	
	private AmazonSimpleDB sdb;

	public void connect(ServletContext context) throws DAOException {
		String propFile = "./config/AwsCredentials.properties";
		try {
			sdb = new AmazonSimpleDBClient(new PropertiesCredentials(context.getResourceAsStream(propFile)));
		} catch (FileNotFoundException e) {
			throw new DAOException("The file " + propFile + " could not be found.");
		} catch (IllegalArgumentException e) {
			throw new DAOException("The file " + propFile + " does not contain the keys required to access the database.");
		} catch (IOException e) {
			throw new DAOException("The file " + propFile + " could not be read.");
		}
	}
	
	public void disconnect() {
		sdb.deleteAttributes(new DeleteAttributesRequest().withDomainName("gameStates"));
	}
	
	public String[] getUsers(boolean loggedIn) {
		List<String> users = new LinkedList<String>();

		String query = "SELECT u_id FROM user WHERE logged_in=\"" + loggedIn + "\"";
		SelectRequest sr = new SelectRequest(query);
		List<Item> items = sdb.select(sr).getItems();
		if (items.isEmpty()) {
			return null;
		} else {
			for (Item item : items) {
				List<Attribute> attrs = item.getAttributes();
				users.add(attrs.get(0).getValue());
			}
			return users.toArray(new String[1]);
		}
	}
	
	public String getUserLoggedIn(String u_id) {		
		String query = "SELECT logged_in FROM user WHERE u_id=\"" + u_id + "\"";
		SelectRequest sr = new SelectRequest(query);
		List<Item> items = sdb.select(sr).getItems();
		if (items.isEmpty()) {
			return "";
		}
		
		List<Attribute> attrs = items.get(0).getAttributes();
		String loggedIn = (String) attrs.get(0).getValue();
		
		return loggedIn;
	}
	
	public void loginUser(String u_id, int g_id, boolean replace) {
		List<ReplaceableAttribute> attr = new LinkedList<ReplaceableAttribute>();
		attr.add(new ReplaceableAttribute("u_id", u_id, replace));
		attr.add(new ReplaceableAttribute("logged_in", "true", replace));
		attr.add(new ReplaceableAttribute("g_id", g_id + "", replace));
		PutAttributesRequest par = new PutAttributesRequest("user", u_id, attr);
		sdb.putAttributes(par);
	}
	
	public void logoutUser(String u_id) {
		List<ReplaceableAttribute> attr = new LinkedList<ReplaceableAttribute>();
		attr.add(new ReplaceableAttribute("logged_in", "false", true));
		attr.add(new ReplaceableAttribute("g_id", "0", true));
		PutAttributesRequest par = new PutAttributesRequest("user", u_id, attr);
		sdb.putAttributes(par);
	}
	
	public void addGroup(int g_id, int e_id, int turn_id) {
		List<ReplaceableAttribute> attr = new LinkedList<ReplaceableAttribute>();
		attr.add(new ReplaceableAttribute().withName("g_id").withValue(g_id + ""));
		attr.add(new ReplaceableAttribute().withName("e_id").withValue(e_id + ""));
		attr.add(new ReplaceableAttribute().withName("turn_id").withValue(turn_id + ""));
		PutAttributesRequest par = new PutAttributesRequest("game", g_id + "", attr);
		sdb.putAttributes(par);
	}
	
	public String[] getGroupMembers(int g_id) {
		List<String> members = new LinkedList<String>();
		String query = "SELECT u_id FROM user WHERE g_id=\"" + g_id + "\"";
		SelectRequest sr = new SelectRequest(query);
		List<Item> items = sdb.select(sr).getItems();
		if (items.isEmpty()) {
			return null;
		} else {
			for (Item item : items) {
				List<Attribute> attrs = item.getAttributes();
				members.add(attrs.get(0).getValue());
			}
			return members.toArray(new String[1]);
		}
	}
	
	public void setEventID(int g_id, int e_id, boolean replace) {
		List<ReplaceableAttribute> attr = new LinkedList<ReplaceableAttribute>();
		attr.add(new ReplaceableAttribute("g_id", g_id + "", replace));
		attr.add(new ReplaceableAttribute("e_id", e_id + "", replace));
		PutAttributesRequest par = new PutAttributesRequest("game", g_id + "", attr);
		sdb.putAttributes(par);
	}
	
	public int getEventID(int g_id) {
		String query = "SELECT e_id FROM game WHERE g_id=\"" + g_id + "\"";
		SelectRequest sr = new SelectRequest(query);
		List<Item> items = sdb.select(sr).getItems();
		if (items.isEmpty()) {
			setEventID(g_id, 0, false);
			return 0;
		}
		
		List<Attribute> attrs = items.get(0).getAttributes();
		int e_id = Integer.parseInt(attrs.get(0).getValue());
		
		return e_id;
	}
	
	public void addGameDeck(int g_id, List<String> deck) {
		int count = 0;
		List<ReplaceableItem> items = new LinkedList<ReplaceableItem>();
		for (String card : deck) {
			count++;
			List<ReplaceableAttribute> attr = new LinkedList<ReplaceableAttribute>();
			attr.add(new ReplaceableAttribute("g_id", g_id + "", false));
			attr.add(new ReplaceableAttribute("position", count + "", false));
			attr.add(new ReplaceableAttribute("card", card, false));
			ReplaceableItem item = new ReplaceableItem(g_id + "-" + count, attr);
			items.add(item);
			if (items.size() == 25) {
				BatchPutAttributesRequest bpar = new BatchPutAttributesRequest("game_deck", items);
				sdb.batchPutAttributes(bpar);
				items.clear();
			}
		}
		if (!items.isEmpty()) {
			BatchPutAttributesRequest bpar = new BatchPutAttributesRequest("game_deck", items);
			sdb.batchPutAttributes(bpar);
		}
	}
	
	public List<String> removeGameDeck(int g_id) {
		Map<Integer, String> deckMap = new TreeMap<Integer, String>();
		String query = "SELECT position, card FROM game_deck WHERE g_id=\"" + g_id + "\"";
		SelectRequest sr = new SelectRequest(query);
		for (Item item : sdb.select(sr).getItems()) {
			List<Attribute> attrs = item.getAttributes();
			deckMap.put(Integer.parseInt(attrs.get(0).getValue()), attrs.get(1).getValue());
		}
		
		List<DeletableItem> items = new LinkedList<DeletableItem>();
		for (int position : deckMap.keySet()) {
			items.add(new DeletableItem(g_id + "-" + position, new LinkedList<Attribute>()));
			if (items.size() == 25) {
				BatchDeleteAttributesRequest bdar = new BatchDeleteAttributesRequest("game_deck", items);
				sdb.batchDeleteAttributes(bdar);
				items.clear();
			}
		}
		BatchDeleteAttributesRequest bdar = new BatchDeleteAttributesRequest("game_deck", items);
		sdb.batchDeleteAttributes(bdar);
		
		List<String> deck = new LinkedList<String>();
		for (int i = 1; i <= deckMap.size(); i++) {
			deck.add(deckMap.get(i));
		}
		return deck;
	}
	
	public void setPlayerHand(String u_id, List<String> hand) throws DAOException{
		List<ReplaceableItem> items = new LinkedList<ReplaceableItem>();
		for (String card : hand) {
			List<ReplaceableAttribute> attr = new LinkedList<ReplaceableAttribute>();
			attr.add(new ReplaceableAttribute("u_id", u_id, false));
			attr.add(new ReplaceableAttribute("card", card, false));
			ReplaceableItem item = new ReplaceableItem(u_id + "-" + card, attr);
			items.add(item);
			if (items.size() == 25) {
				BatchPutAttributesRequest bpar = new BatchPutAttributesRequest("player_hand", items);
				sdb.batchPutAttributes(bpar);
				items.clear();
			}
		}
		
		if (!items.isEmpty()) {
			BatchPutAttributesRequest bpar = new BatchPutAttributesRequest("player_hand", items);
			sdb.batchPutAttributes(bpar);
		}
	}
	
	public List<String> getPlayerHand(String u_id) {
		List<String> hand = new LinkedList<String>();
		String query = "SELECT card FROM player_hand WHERE u_id=\"" + u_id + "\"";
		SelectRequest sr = new SelectRequest(query);
		for (Item item : sdb.select(sr).getItems()) {
			List<Attribute> attrs = item.getAttributes();
			hand.add(attrs.get(0).getValue());
		}
		return hand;
	}
	
	public void addCardToPlayerHand(String u_id, String c_id) {
		List<ReplaceableAttribute> attr = new LinkedList<ReplaceableAttribute>();
		attr.add(new ReplaceableAttribute("u_id", u_id, false));
		attr.add(new ReplaceableAttribute("card", c_id, false));
		PutAttributesRequest par = new PutAttributesRequest("player_hand", u_id + "-" + c_id, attr);
		sdb.putAttributes(par);
	}
	
	public String removeCardFromPlayerHand(String u_id, String c_id) {
		String card = "";
		List<String> hand = getPlayerHand(u_id);
		for (String c : hand) {
			if (c.contains(c_id.charAt(0) + "")) {
				card = c;
				hand.remove(c);
				break;
			}
		}
		
		DeleteAttributesRequest dar = new DeleteAttributesRequest("player_hand", u_id + "-" + card);
		sdb.deleteAttributes(dar);
		
		return card;
	}
	
	public void clearPlayerHand(int g_id) {
		List<DeletableItem> items = new LinkedList<DeletableItem>();
		String[] users = getGroupMembers(g_id);
		for (String u_id : users) {
			List<String> hand = getPlayerHand(u_id);
			if (!hand.isEmpty()) {
				for (String card : hand) {
					items.add(new DeletableItem(u_id + "-" + card, new LinkedList<Attribute>()));
				}
			}
		}
		BatchDeleteAttributesRequest bdar = new BatchDeleteAttributesRequest("player_hand", items);
		sdb.batchDeleteAttributes(bdar);
	}
	
	public void addCardToPlayerPairs(String u_id, String c_id) {
		List<ReplaceableAttribute> attr = new LinkedList<ReplaceableAttribute>();
		attr.add(new ReplaceableAttribute("u_id", u_id, false));
		attr.add(new ReplaceableAttribute("card", c_id, false));
		PutAttributesRequest par = new PutAttributesRequest("player_pairs", u_id + "-" + c_id, attr);
		sdb.putAttributes(par);
	}
	
	public List<String> getPlayerPairs(String u_id) {
		List<String> pairs = new LinkedList<String>();
		String query = "SELECT card FROM player_pairs WHERE u_id=\"" + u_id + "\"";
		SelectRequest sr = new SelectRequest(query);
		for (Item item : sdb.select(sr).getItems()) {
			List<Attribute> attrs = item.getAttributes();
			pairs.add(attrs.get(0).getValue());
		}
		return pairs;
	}
	
	public void clearPlayerPairs(int g_id) {
		List<DeletableItem> items = new LinkedList<DeletableItem>();
		String[] users = getGroupMembers(g_id);
		for (String u_id : users) {
			List<String> pairs = getPlayerPairs(u_id);
			if (!pairs.isEmpty()) {
				for (String card : pairs) {
					items.add(new DeletableItem(u_id + "-" + card, new LinkedList<Attribute>()));
				}
			}
		}
		BatchDeleteAttributesRequest bdar = new BatchDeleteAttributesRequest("player_pairs", items);
		sdb.batchDeleteAttributes(bdar);
	}
	
	public int getGameTurnID(int g_id) {
		String query = "SELECT turn_id FROM game WHERE g_id=\"" + g_id + "\"";
		SelectRequest sr = new SelectRequest(query);
		List<Item> items = sdb.select(sr).getItems();
		
		if (items.isEmpty()) {
			setGameTurnID(g_id, 0, false);
			return 0;
		}
		
		List<Attribute> attrs = items.get(0).getAttributes();
		int turn_id = Integer.parseInt(attrs.get(0).getValue());
		
		return turn_id;
	}
	
	public void setGameTurnID(int g_id, int turn_id, boolean replace) {
		List<ReplaceableAttribute> attr = new LinkedList<ReplaceableAttribute>();
//		attr.add(new ReplaceableAttribute("g_id", g_id + "", replace));
		attr.add(new ReplaceableAttribute("turn_id", turn_id + "", replace));
		PutAttributesRequest par = new PutAttributesRequest("game", g_id + "", attr);
		sdb.putAttributes(par);
	}
	
	public void clearGameData(int g_id) {
		DeleteAttributesRequest dar = new DeleteAttributesRequest("game", g_id + "");
		sdb.deleteAttributes(dar);
	}
	
	public String getCardInPlayerHand(String u_id, String c_id) {
		String query = "SELECT card FROM player_hand WHERE u_id=\"" + u_id + "\"";
		SelectRequest sr = new SelectRequest(query);
		for (Item item : sdb.select(sr).getItems()) {
			List<Attribute> attrs = item.getAttributes();
			String card = attrs.get(0).getValue();
			if (attrs.get(0).getValue().contains(c_id.charAt(0) + "")) {
				return card;
			}
		}
		
		return "";
	}
	
	public int getPlayerHandSize(String u_id) {
		String query = "SELECT COUNT(*) FROM player_hand WHERE u_id=\"" + u_id + "\"";
		SelectRequest sr = new SelectRequest(query);
		List<Attribute> attrs = sdb.select(sr).getItems().get(0).getAttributes();
		int size = Integer.parseInt(attrs.get(0).getValue());
		return size;
	}
	
	public int getGameDeckSize(int g_id) {
		String query = "SELECT COUNT(*) FROM game_deck WHERE g_id=\"" + g_id + "\"";
		SelectRequest sr = new SelectRequest(query);
		List<Attribute> attrs = sdb.select(sr).getItems().get(0).getAttributes();
		int size = Integer.parseInt(attrs.get(0).getValue());
		return size;
	}
	
	public String removeTopCardFromDeck(int g_id) {
		//String query = "SELECT card FROM game_deck WHERE g_id=\"" + g_id + "\" AND position=\"1\"";
		//SelectRequest sr = new SelectRequest(query);
		//List<Attribute> attrs = sdb.select(sr).getItems().get(0).getAttributes();
		//String card = attrs.get(0).getValue();
		
		//DeleteAttributesRequest dar = new DeleteAttributesRequest("game_deck", g_id + "-1");
		//sdb.deleteAttributes(dar);
		List<String> deck = new LinkedList<String>();
		
		String query = "SELECT card FROM game_deck WHERE g_id=\"" + g_id + "\"";
		SelectRequest sr = new SelectRequest(query);
		List<Item> items = sdb.select(sr).getItems();
		
		if (items.isEmpty()) {
			return null;
		} else {
			String card = items.get(0).getAttributes().get(0).getValue();
			items.remove(0);
			for (Item item : items) {
				deck.add(item.getAttributes().get(0).getValue());
			}
			removeGameDeck(g_id);
			addGameDeck(g_id, deck);
			return card;
		}
	}
	
	public void setGameEventString(int g_id, String event) {
		List<ReplaceableAttribute> attr = new LinkedList<ReplaceableAttribute>();
		attr.add(new ReplaceableAttribute("event", event, true));
		PutAttributesRequest par = new PutAttributesRequest("game", g_id + "", attr);
		sdb.putAttributes(par);
	}
	
	public String getGameEventString(int g_id) {
		String query = "SELECT event FROM game WHERE g_id=\"" + g_id + "\"";
		SelectRequest sr = new SelectRequest(query);
		List<Attribute> attrs = sdb.select(sr).getItems().get(0).getAttributes();
		if (attrs.isEmpty()) {
			return null;
		}
		return attrs.get(0).getValue();
	}
}
